package com.quectel.cms.controller.home;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.business.common.util.sys.SysCodeUtils;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.util.SessionHolder;
import com.quectel.cms.vo.home.*;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.sys.SysCodeKeyConstants;
import com.quectel.core.module.partybuilding.dto.PartyOrganizationDto;
import com.quectel.core.module.partybuilding.dto.PartyPersonDto;
import com.quectel.core.module.partybuilding.service.PartyOrganizationService;
import com.quectel.core.module.partybuilding.service.PartyPersonService;
import com.quectel.core.module.partybuildingactivity.service.PartyBuildingActivityService;
import com.quectel.core.module.partybuildingmeeting.dto.PartyBuildingMeetingDto;
import com.quectel.core.module.partybuildingmeeting.service.PartyBuildingMeetingService;
import com.quectel.sys.module.sys.dto.SysCodeDto;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bob
 * @email bob.yu@quectel.com
 * @date 2023/06/21 14:42
 */
@RestController
@RequestMapping("home/partyBuilding")
@Tag(name = "HomePartyBuildingController", description = "党建管理首页相关api")
@Slf4j
public class HomePartyBuildingController extends BaseController {

    public static final Byte RNAGE_UNUSE = -1;
    public static final Byte RANGE_ONE=1;
    public static final Byte RANGE_TWO = 2;
    public static final Byte RANGE_THREE =3;
    public static final Byte RANGE_FOUR = 4;
    public static final Byte RANGE_FIVE = 5;

    @DubboReference
    private PartyPersonService partyPersonService;
    @DubboReference
    private PartyOrganizationService partyOrganizationService;
    @DubboReference
    private PartyBuildingActivityService activityService;
    @DubboReference
    private PartyBuildingMeetingService meetingService;

    /**
     * 党员年龄分布
     * 18-30岁
     * 31-40岁
     * 41-50岁
     * 51-60岁
     * 61岁以上
     */
    @GetMapping("partyPersonAgeStatistics")
    @Operation(summary = "党员年龄分组- type类型: 1(18-30岁) 2(31-40岁) 3(41-50岁) 4(51-60岁) 5(61岁以上)")
    public Response<List<OrganizationPersonCountVo>> partyPersonAgeStatistics(){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        List<PartyPersonDto> partyPersonDtoList = partyPersonService.queryList(request.getParams());

        Map<Byte, Integer> ageRangeCountMap = partyPersonDtoList.stream()
                .filter(partyPersonDto -> partyPersonDto.getBirthDate() != null)
                .collect(Collectors.groupingBy(partyPersonDto -> calculateAgeRange(partyPersonDto.getBirthDate()), Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));

        ageRangeCountMap.remove(RNAGE_UNUSE);
        ageRangeCountMap.merge(RANGE_ONE, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_TWO, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_THREE, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_FOUR, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_FIVE, 0, Integer::sum);

        List<OrganizationPersonCountVo> organizationPersonCountVoList = ageRangeCountMap.entrySet().stream()
                .map(entry -> {
                    OrganizationPersonCountVo organizationPersonCountVo = new OrganizationPersonCountVo();
                    organizationPersonCountVo.setType(entry.getKey());
                    organizationPersonCountVo.setCount(entry.getValue());
                    return organizationPersonCountVo;
                })
                .collect(Collectors.toList());

        return Response.<List<OrganizationPersonCountVo>>ok().wrap(organizationPersonCountVoList);
    }

    /**
     * 党龄分布
     * 0-5年
     * 5-10年
     * 10-15年
     * 15-20年
     * 20年以上
     */
    @GetMapping("partyYearStatistics")
    @Operation(summary = "党员党龄分组- type:1(0-5年) 2(5-10年) 3(10-15年) 4(15-20年) 5(20年以上)")
    public Response<List<OrganizationPersonCountVo>> partyYearStatistics(){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        List<PartyPersonDto> partyPersonDtoList = partyPersonService.queryList(request.getParams());

        Map<Byte, Integer> ageRangeCountMap = partyPersonDtoList.stream()
                .filter(partyPersonDto -> partyPersonDto.getProbationTime() != null)
                .collect(Collectors.groupingBy(partyPersonDto -> calculateProbationTimeRange(partyPersonDto.getProbationTime()),
                        Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));

            ageRangeCountMap.merge(RANGE_ONE, 0, Integer::sum);
            ageRangeCountMap.merge(RANGE_TWO, 0, Integer::sum);
            ageRangeCountMap.merge(RANGE_THREE, 0, Integer::sum);
            ageRangeCountMap.merge(RANGE_FOUR, 0, Integer::sum);
            ageRangeCountMap.merge(RANGE_FIVE, 0, Integer::sum);

        List<OrganizationPersonCountVo> organizationPersonCountVoList = ageRangeCountMap.entrySet().stream()
                .map(entry -> {
                    OrganizationPersonCountVo organizationPersonCountVo = new OrganizationPersonCountVo();
                    organizationPersonCountVo.setType(entry.getKey());
                    organizationPersonCountVo.setCount(entry.getValue());
                    return organizationPersonCountVo;
                })
                .collect(Collectors.toList());

        return Response.<List<OrganizationPersonCountVo>>ok().wrap(organizationPersonCountVoList);
    }

    /**
     * 各党组织党员数量
     */
    @GetMapping("organizationPersonStatistics")
    @Operation(summary = "各党组织党员数量")
    public Response<List<OrganizationPersonCountVo>> organizationPersonStatistics(){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        List<OrganizationPersonCountVo> resultList = new ArrayList<>();
        List<PartyOrganizationDto> organizationList = partyOrganizationService.queryList(request.getParams());
        Map<String,Object> sqlMap = new HashMap<>();

        if (CollectionUtils.isNotEmpty(organizationList)){
            for (PartyOrganizationDto organizationDto : organizationList) {
                if (!organizationDto.getParentId().equals(SystemConstants.TREE_DEFAULT_PARENT_ID)){
                    sqlMap.put(LambdaUtil.getFieldName(PartyPersonDto::getPartyId), organizationDto.getId());
                    int queryTotal = partyPersonService.queryTotal(sqlMap);
                    OrganizationPersonCountVo addVo = new OrganizationPersonCountVo();
                    addVo.setName(organizationDto.getName());
                    addVo.setCount(queryTotal);
                    resultList.add(addVo);
                }
            }
        }

        return Response.<List<OrganizationPersonCountVo>>ok().wrap(resultList);
    }


    /**
     * 三会一课统计
     */
    @GetMapping("meetingStatistics")
    @Operation(summary = "三会一课统计")
    public Response<List<PartyBuildingMeetingStaticsVo>> eduStatics() {
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        Long partyId = SessionHolder.getSysUser().getPartyId();

        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingMeetingDto::getPartyId),partyId);
        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingMeetingDto::getCategory), SystemConstants.YES);

        List<SysCodeDto> categoryCodeList = SysCodeUtils.easyToGetByMark("ThreeOneLesson");
        List<PartyBuildingMeetingStaticsVo> eventList = new ArrayList<>();
        for (SysCodeDto sysCodeDto : categoryCodeList) {
            PartyBuildingMeetingStaticsVo pieInfo = new PartyBuildingMeetingStaticsVo();
            pieInfo.setName(sysCodeDto.getName());
            request.put(LambdaUtil.getFieldName(PartyBuildingMeetingDto::getType), sysCodeDto.getValue());

            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtil.format(DateUtil.beginOfMonth(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getRight(),DateUtil.format(DateUtil.endOfMonth(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            int monthCount = meetingService.queryTotal(request.getParams());
            pieInfo.setThisMonth(monthCount);

            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtil.format(DateUtil.beginOfYear(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getRight(),DateUtil.format(DateUtil.endOfYear(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            int yearCount = meetingService.queryTotal(request.getParams());
            pieInfo.setThisYear(yearCount);
            eventList.add(pieInfo);
        }
        return Response.<List<PartyBuildingMeetingStaticsVo>>ok().wrap(eventList);
    }


    /**
     * 籍贯分布-取省数据
     */
    @GetMapping("nationPlaceStatistics")
    @Operation(summary = "籍贯分布")
    public Response<List<PartyPersonNationPlaceCountVo>> nationPlaceStatistics() {
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        List<PartyPersonDto> partyPersonDtoList = partyPersonService.queryList(request.getParams());

        List<PartyPersonDto> collect =
                partyPersonDtoList.stream()
                        .filter(partyPersonDto -> partyPersonDto.getNativePlace() != null).collect(Collectors.toList());

        List<PartyPersonNationPlaceCountVo> respList = collect.stream()
                .collect(Collectors.groupingBy(PartyPersonDto::getNativePlace, Collectors.counting()))
                .entrySet()
                .stream()
                .map(entry -> {
                    PartyPersonNationPlaceCountVo nationPlaceCountVo = new PartyPersonNationPlaceCountVo();
                    nationPlaceCountVo.setCode(entry.getKey());
                    nationPlaceCountVo.setCount(entry.getValue().intValue());
                    return nationPlaceCountVo;
                })
                .collect(Collectors.toList());

        return Response.<List<PartyPersonNationPlaceCountVo>>ok().wrap(respList);
    }

    /**
     * 学历分布
     */
    @GetMapping("eduStatistics")
    @Operation(summary = "学历分布")
    public Response<List<WorkOrderCountVo>> eduStatistics() {
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        List<SysCodeDto> categoryCodeList = SysCodeUtils.easyToGetByMark(SysCodeKeyConstants.PARTY_PERSON_EDUCATION);
        List<WorkOrderCountVo> eventList = new ArrayList<>();
        for (SysCodeDto sysCodeDto : categoryCodeList) {
            WorkOrderCountVo pieInfo = new WorkOrderCountVo();
            pieInfo.setName(sysCodeDto.getName());
            request.put(LambdaUtil.getFieldName(PartyPersonDto::getEducation), sysCodeDto.getValue());
            int count = partyPersonService.queryTotal(request.getParams());
            pieInfo.setCount(count);
            eventList.add(pieInfo);
        }
        return Response.<List<WorkOrderCountVo>>ok().wrap(eventList);
    }


    /**
     * 智慧党建首页-多维度数量统计
     * @return
     */
    @GetMapping("statisticsInfo")
    @Operation(summary = "智慧党建首页-多维度数量统计")
    public Response<PartyBuildingStatisticsInfoVo> propertyStatisticsInfo() {

        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        int partyorganizationCount = partyOrganizationService.queryTotal(request.getParams());

        // 党员统计调整 = 正式党员+预备党员
        // 正式 1  预备2
        request.getParams().put(LambdaUtil.getFieldName(PartyPersonDto::getPersonIdentity), 1);
        int formalNum = partyPersonService.queryTotal(request.getParams());

        request.getParams().put(LambdaUtil.getFieldName(PartyPersonDto::getPersonIdentity), 2);
        int preparationNum = partyPersonService.queryTotal(request.getParams());

        int partyPersonCount =  formalNum + preparationNum;

        // 男性
        request.put(LambdaUtil.getFieldName(PartyPersonDto::getGender), SystemConstants.MALE);
        int manCount = partyPersonService.queryTotal(request.getParams());
        // 女性
        request.put(LambdaUtil.getFieldName(PartyPersonDto::getGender), SystemConstants.FEMALE);
        int womanCount = partyPersonService.queryTotal(request.getParams());

        request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getGender));

        request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtil.format(DateUtil.beginOfMonth(new Date()), DatePattern.NORM_DATETIME_PATTERN));
        request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getRight(),DateUtil.format(DateUtil.endOfMonth(new Date()), DatePattern.NORM_DATETIME_PATTERN));
        int partyBuildingMeetingCount = meetingService.queryTotal(request.getParams());
        int partyBuildingActivityCount = activityService.queryTotal(request.getParams());


        PartyBuildingStatisticsInfoVo vo = new PartyBuildingStatisticsInfoVo();
        vo.setPartyorganizationCount(partyorganizationCount);
        vo.setPartyPersonCount(partyPersonCount);
        vo.setManCount(manCount);
        vo.setWomanCount(womanCount);
        vo.setPartyBuildingMeetingCount(partyBuildingMeetingCount);
        vo.setPartyBuildingActivityCount(partyBuildingActivityCount);

        return Response.<PartyBuildingStatisticsInfoVo>ok().wrap(vo);
    }

    // 计算党员党龄范围
    private Byte calculateProbationTimeRange(Date probationTime) {
        LocalDate currentDate = LocalDate.now();
        LocalDate probationDate = probationTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Period period = Period.between(probationDate, currentDate);
        int years = period.getYears();

        if (years >= 0 && years <= 5) {
            return RANGE_ONE;
        } else if (years > 5 && years <= 10) {
            return RANGE_TWO;
        } else if (years > 10 && years <= 15) {
            return RANGE_THREE;
        } else if (years > 15 && years <= 20) {
            return RANGE_FOUR;
        } else {
            return RANGE_FIVE;
        }
    }

    // 计算党员年龄范围
    private Byte calculateAgeRange(Date birthDate) {
        LocalDate currentDate = LocalDate.now();
        LocalDate probationDate = birthDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Period period = Period.between(probationDate, currentDate);
        int age = period.getYears();

        if (age >= 18 && age <= 30) {
            return RANGE_ONE;
        } else if (age > 30 && age <= 40) {
            return RANGE_TWO;
        } else if (age > 40 && age <= 50) {
            return RANGE_THREE;
        } else if (age > 50 && age <= 60) {
            return RANGE_FOUR;
        } else if (age > 60){
            return RANGE_FIVE;
        }else {
            return RNAGE_UNUSE;
        }
    }
}
